<?php
	abstract class AbstractImportController extends AppController
	{
		var $abstractView = "import.import";
		var $helpers = array("Html","Form");
		var $modelAlias = false;
		
		function import()
		{
			$this->pageTitle = __("Upload CSV File");
			$allowLocalFiles = $this->getImportModel()->allowLocalFiles();
			if($this->data)
			{
				$useLocalFile = false;
				$localFile = false;
				
				if($allowLocalFiles && isset($this->data[$this->getImportModel()->alias]['use_local']) && $this->data[$this->getImportModel()->alias]['use_local'])
				{
					
					$useLocalFile = true;
					$localFile = $this->data[$this->getImportModel()->alias]['local_file'];
					unset($this->data[$this->getImportModel()->alias]['file']);
				}else if(!isset($this->data[$this->getImportModel()->alias]['file']))
				{
					$this->data[$this->getImportModel()->alias]['file'] = "";
				}
				$this->getImportModel()->set($this->data);
				if($this->getImportModel()->validates())
				{
					if($useLocalFile == false)
					{
						$savedData = $this->getImportModel()->save($this->data,array("validates"=>false));
						$savedData = ($this->getImportModel()->data);
						$realFileName = $this->getImportModel()->data[$this->getImportModel()->alias]['file_uploadInfo']['filename'];
						$filePath = @$savedData[$this->getImportModel()->alias]['file_uploadInfo']['fullpath'];
					}else
					{
						$localFiles	= $this->getImportModel()->getLocalCsvFiles();
						if(in_array($localFile,$localFiles))
						{
							$realFileName = $localFile;
							$filePath = $this->getImportModel()->copyLocalFile($localFile);
						}else
						{
							$filePath = false;
						}
					}
					if($filePath != false && is_file($filePath))
					{
						$importData = $this->data[$this->getImportModel()->alias];
						$importData['actual_file_name'] = $realFileName;
						$importInformation = array('hasHeaders'=>$this->data[$this->getImportModel()->alias]['has_headers'],'importData'=>$importData);
						$importFileId = $this->getImportModel()->addNewImportFile($filePath,$importInformation);
						$this->redirect(array("action"=>"parse",$importFileId));
					}
					
				}else
				{
					$this->errorMsg(__("Please fix the error below."));
				}
			}
			if($allowLocalFiles)
			{
				$this->set("localFiles",$this->getImportModel()->getLocalCsvFiles());
			}
			if(!$this->data)
			{
				$pendingImports = $this->getImportModel()->getFileModel()->getPending();
				$this->set("pendingImports",$pendingImports);
			}
		}
		
		function parse($fileId)
		{
			$this->pageTitle = __("Select Fields");
			$fileInfo = $this->getImportModel()->getFileModel()->getFileInfo($fileId);
			if(!$fileInfo || $fileInfo['is_active'])
			{
				$this->redirect(array("action"=>"import"));
			}
			$filePath = $fileInfo['full_path'];
			$hasHeaders = $fileInfo['other_information']['hasHeaders'];
			$fileHandle = fopen($filePath,"r");
			$firstLine = fgetcsv($fileHandle);
			fclose($fileHandle);
			$headers = array();
			if($hasHeaders)
			{
				$headers = $firstLine;
			}else
			{
				for($i =1;$i <= count($firstLine);$i++)
				{
					$headers[] = sprintf("Column #%d",$i);
				}
			}
			$this->set("headers",$headers);
			if($this->data)
			{
				$fieldMap = $this->data[$this->getImportModel()->alias]['fields'];
				array_filter($fieldMap);
				$requiredFields = $this->getImportModel()->getImportRequiredFields();
				
				$requiredFieldsNotPresent = array_diff($requiredFields,$fieldMap);
				$this->set("requiredFieldsNotPresent",$requiredFieldsNotPresent);
				if(count($requiredFieldsNotPresent) == 0 && count($fieldMap) > 0 )
				{
					$this->getImportModel()->getFileModel()->setFieldMap($fileId,$fieldMap);
					$this->Session->write($this->name.'.fieldMap',$fieldMap);
					$this->redirect(array("action"=>"startImporting",$fileId));
				}
			}
		}
		/**
		 * 
		 * @return @var AbstractImport
		 */
		protected function getImportModel()
		{
			if($this->modelAlias)
			{
				$Model = $this->{$this->modelAlias};
			}else
			{
				$Model = $this->{$this->uses[0]};
			}
			return $Model;
		}
		
		function startImporting($fileId)
		{
			$this->pageTitle = __("Import");
			$fileInfo = $this->getImportModel()->getFileModel()->getFileInfo($fileId);
			if(!$fileInfo || $fileInfo['is_completed'])
			{
				$this->redirect(array("action" => "import"));
			}
			if(!is_array($fileInfo['fields_map']) || count($fileInfo['fields_map']) < 1)
			{
				$this->warningMsg(__("Please assign fields first."));
				$this->redirect(array("action"=>"parse",$fileId));
			}
			$this->set("fileId",$fileId);
			$this->set("fileInfo",$fileInfo);
			
		}
		function runBatch($fileId,$batchSize = 100)
		{
			$this->__runBatchProcess($fileId,$batchSize);
		}
		final protected function __runBatchProcess($fileId,$batchSize = 100)
		{
			set_time_limit(0);
			$batchSize = abs($batchSize);
			$lastRowNumber = 0;
			if($batchSize < 1)
			{
				$batchSize = 10;
			}else if($batchSize > 500)
			{
				$batchSize = 200;
			}
			ob_start();
			$ok = true;
			$completed = false;
			$FileModel = $this->getImportModel()->getFileModel();
			$fileInfo = $FileModel->getFileInfo($fileId);
			$file = null;
			if(!$fileInfo)
			{
				$fileInfo = array();
			}
			$file = $fileInfo['full_path'];
			if(!$fileInfo || !is_file($file) || !is_array($fileInfo['fields_map']) || count($fileInfo['fields_map']) < 1)
			{
				echo __("Invalid File");
				$ok = false;
			}else if($fileInfo['is_completed'])
			{
				echo __("Importing Completed.");
				$ok = true;
				$completed = true;
			}else if($FileModel->isRunning($fileId,$fileInfo))
			{
				echo __("Another batch is still running.");
				$ok = true;
			}
			//now process
			else
			{
				$handle = fopen($file,"r+");
				//this migh cauause probelm 
				$fileOffset = $FileModel->field("file_offset",array("id"=>$fileId));
				if(!strlen($fileOffset))
				{
					$fileOffset = 0;
				}
				$fileOffset = (int)$fileOffset;
				rewind($handle);
				fseek($handle, $fileOffset);
				$hasHeaders = $fileInfo['other_information']['hasHeaders'];
				$FileModel->flagAsRunning($fileId);
				if($hasHeaders && !$fileInfo['is_active'])
				{
					$line = fgetcsv($handle);
					$this->truncateTillSeeked($handle);
				}
				$lastRowNumber = $fileInfo['last_row_number'];
				$this->beforeBatchStart($fileId,$fileInfo);
				for($i = 1 ;$i <= $batchSize;$i++)
				{
					$line = fgetcsv($handle);
					if(!$line)
					{
						$completed = true;
						break;
					}
					$saved = $this->saveCsvLine($fileInfo, $line);
					if($saved === true)
					{
						echo "\n Saved a New Record with id:".$this->getImportModel()->getImporterModel()->id;
					}else
					{
						echo "\n Not able to save row number : ".$lastRowNumber;
						$this->log(array('line'=>$line,'errors'=>$saved),"csv_import/".'file_'.$fileId);
					}
					$FileModel->id = $fileId;
					$FileModel->saveField('file_offset',ftell($handle));
					if($i % 5 == 0)
					{
						sleep(1);
					}
					//$this->truncateTillSeeked($handle,$file);
					echo "\n";
					$lastRowNumber++;
				}
				fclose($handle);
				$this->afterBatchFinish($fileId,$fileInfo);
				$FileModel->removeRunningFlag($fileId,$completed,$lastRowNumber);
			}
			$logs = ob_get_clean();
			Configure::write("debug",0);
			echo json_encode(array('ok'=>$ok,'logs'=>$logs,'lastRowNumber'=>'"'.$lastRowNumber.' "','completed'=>$completed));
			$this->autoRender = false;
			$this->_stop();
		}
		function deleteImportFile($fileId)
		{
			if($fileId)
			{
				$FileModel = $this->getImportModel()->getFileModel();
				$FileModel->delete($fileId);
				$this->successMsg(__("File has been deleted."));
			}
			$this->redirect(array("action"=>"import"));
		}
		final protected function truncateTillSeeked($handle,$fileName = null)
		{return;
		//not a good solution.
			$position = ftell($handle);
			$filesize = filesize($fileName);
			$positionLengthContent = "";
			for($i=0 ; $i < $position;$i++)
			{
				$char = fgetc($handle);
				if($char === false)
				{
					break;
				}
				$positionLengthContent .= $char;
			}
			$position = strlen($positionLengthContent);
			rewind($handle);
			
			if($position > 0)
			{
				//ftruncate($handle,$position);	
			}
			exit;
		}
		protected function beforeRowInsert($fileInfo,$data)
		{
			
		}
		protected function afterRowInsert($fileInfo,$saved)
		{
			
		}
		protected function beforeBatchStart($fileId,$fileInfo)
		{
			
		}
		
		protected function afterBatchFinish($fileId,$fileInfo)
		{
			
		}
		protected function saveCsvLine($fileInfo,$csvLine)
		{
			$fieldsMap = $fileInfo['fields_map'];
			$data = false;
			$importFields = $this->getImportModel()->getImportFields();
			foreach($csvLine as $key => $column)
			{
				if(!isset($fieldsMap[$key]) || !in_array($fieldsMap[$key],$importFields))
				{
						continue;
				}
				$field = $fieldsMap[$key];
				$data[$field] = $column;
			}
			$this->beforeRowInsert($fileInfo, $data);
			$saved = $this->saveToModel($data,$fileInfo);
			$this->afterRowInsert($fileInfo,$saved);
			return $saved;
		}
		
		protected function saveToModel($data,$fileInfo)
		{
			$return  = true;
			if(is_array($data))
			{
				$saved = $this->getImportModel()->saveToImporterModel($data);
			}else
			{
				$saved = false;
			}
			return $saved;
		}
		
		function beforeRender()
		{
			$this->set("importModelAlias",$this->getImportModel()->alias);
			parent::beforeRender();
		}
	}
?>